package org.example.concurrentUtils;

import lombok.SneakyThrows;

import java.io.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.LongAdder;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * @author ZhengDp
 * @Date 2023/2/22 21:56
 */
public class ConcurrentHashMapTest {

    private static final String ALPHA = "abcdefghyjklmnopqrstuvwxyz";

    public static void main(String[] args) {
        demo(() -> new ConcurrentHashMap<String, LongAdder>(),
                (map,words) -> {
                    for(String word : words){
                        // 如果缺少key，则计算生成值，将生成的key value 放入map中
                        // 该方法保证原子性
                        LongAdder value = map.computeIfAbsent(word, key -> new LongAdder());
                        // 累加器保证累加原子性
                        value.increment();
                    }
                });
    }

    private static <V> void demo(Supplier<Map<String,V>> supplier, BiConsumer<Map<String,V>,List<String>> consumer) {
        // key : 单词 value : 出现次数
        Map<String,V> counterMap = supplier.get();
        List<Thread> ts = new ArrayList<>();
        for(int i = 1 ; i<= 26;i++){
            int idx = i;
            Thread thread = new Thread(() -> {
                List<String> words = readFromFile(idx);
                // 26个线程都将结果放到 Map集合中，需要考虑如何保证它的线程安全
                consumer.accept(counterMap,words);
            });
            ts.add(thread);
        }
        ts.forEach(Thread::start);
        ts.forEach(t -> {
            try{
                t.join();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        System.out.println(counterMap);
    }

    /**
     * 读取文件内容，生成字符串集合
     */
    private static List<String> readFromFile(int i) {
        ArrayList<String> words = new ArrayList<>();
        try (BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream("thread/tmp/" + i +".txt")))) {
            while(true) {
                String word = in.readLine();
                if(word == null) {
                    break;
                }
                words.add(word);
            }
            return words;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 生成测试数据
     */
    private static void buildTestData() {
        int length = ALPHA.length();
        int count = 200;
        List<String> list = new ArrayList<>(length * count);

        for( int i = 0 ; i < length ; i ++ ) {
            char ch = ALPHA.charAt(i);
            for ( int j =0 ; j < count ; j ++ ){
                list.add(String.valueOf(ch));
            }
        }
        // 打乱字母
        Collections.shuffle(list);
        // 将内容存入到26个文件中
        for(int i = 0 ;i < 26 ; i ++ ) {
            try(PrintWriter out = new PrintWriter(new OutputStreamWriter(new FileOutputStream("thread/tmp/" + (i + 1) + ".txt")))) {
                String collect = String.join("\n", list.subList(i * count, (i + 1) * count));
                out.println(collect);
            } catch (FileNotFoundException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
